/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package proyecto2;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Observable;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

/**
 *
 * @author Damian L
 */
public class Servidor extends Observable {

    private ObjectOutputStream salida;
    private ObjectInputStream entrada;
    private ServerSocket servidor;
    private Socket conexion;
    private int contador = 1;
    String msg = "";
    int puerto;
    Thread h;
    // configurar GUI

    public Servidor(int puerto) {
        this.puerto = puerto;
        Runnable hilo = new Runnable() {
            @Override
            public void run() {
                ejecutarServidor();
            }
        };

        h = new Thread(hilo);
        h.start();

        // crear campoIntroducir y registrar componente de escucha

//      campoIntroducir.addActionListener(
//         new ActionListener() {
//
//            // enviar mensaje al cliente
//            public void actionPerformed( ActionEvent evento )
//            {
//               enviarDatos( evento.getActionCommand() );
//               campoIntroducir.setText( "" );
//            }
//         }  
//      ); 



    } // fin del constructor de Servidor

    // configurar y ejecutar el servidor 
    public void ejecutarServidor() {
        // configurar servidor para que reciba conexiones; procesar las conexiones
        try {
            // Paso 1: crear un objeto ServerSocket.
            servidor = new ServerSocket(puerto, 100);
            while (true) {
                try {
                    esperarConexion(); // Paso 2: esperar una conexión.
                    obtenerFlujos();        // Paso 3: obtener flujos de entrada y salida.
                    procesarConexion(); // Paso 4: procesar la conexión.
                } // procesar excepción EOFException cuando el cliente cierre la conexión 
                catch (EOFException excepcionEOF) {
                    System.err.println("El servidor terminó la conexión");
                } finally {
                    cerrarConexion();   // Paso 5: cerrar la conexión.
                    ++contador;
                }
            } // fin de instrucción while
        } // fin del bloque try
        // procesar problemas con E/S
        catch (IOException excepcionES) {
            excepcionES.printStackTrace();
        }

    } // fin del método ejecutarServidor

    // esperar que la conexión llegue, después mostrar información de la conexión
    private void esperarConexion() throws IOException {
        mostrarMensaje("Esperando una conexión\n");
        conexion = servidor.accept(); // permitir al servidor aceptar la conexión            
        mostrarMensaje("Conexión " + contador + " recibida de: "
                + conexion.getInetAddress().getHostName());
    }

    // obtener flujos para enviar y recibir datos
    private void obtenerFlujos() throws IOException {
        // establecer flujo de salida para los objetos
        salida = new ObjectOutputStream(conexion.getOutputStream());
        salida.flush(); // vaciar búfer de salida para enviar información de encabezado

        // establecer flujo de entrada para los objetos
        entrada = new ObjectInputStream(conexion.getInputStream());

        mostrarMensaje("\nSe recibieron los flujos de E/S\n");
    }

    // procesar la conexión con el cliente
    private void procesarConexion() throws IOException {
        // enviar mensaje de conexión exitosa al cliente
        String mensaje = "Conexión exitosa";
        enviarDatos(mensaje);
        do { // procesar los mensajes enviados por el cliente
            // leer el mensaje y mostrarlo en pantalla
            try {
                mensaje = (String) entrada.readObject();
                msg = mensaje;
                mostrarMensaje("\n" + mensaje);
                System.out.println("Servidor");
                this.setChanged();
                this.notifyObservers();
            } // atrapar problemas que pueden ocurrir al tratar de leer del cliente
            catch (ClassNotFoundException excepcionClaseNoEncontrada) {
                mostrarMensaje("\nSe recibió un tipo de objeto desconocido");
            } catch (SocketException se) {
                System.out.println("Desconectado");
                JOptionPane.showMessageDialog(null, "Se perdio la conexion");
                System.exit(0);
                h.stop();
            }
        } while (!mensaje.equals("CLIENTE>>> TERMINAR"));
    } // fin del método procesarConexion

    // cerrar flujos y socket
    private void cerrarConexion() {
        mostrarMensaje("\nFinalizando la conexión\n");
        try {
            salida.close();
            entrada.close();
            conexion.close();
        } catch (IOException excepcionES) {
            excepcionES.printStackTrace();
        }
    }
    // enviar mensaje al cliente

    void enviarDatos(String mensaje) {
        // enviar objeto al cliente
        try {
            salida.writeObject(mensaje);
            salida.flush();
            mostrarMensaje("\nSERVIDOR>>> " + mensaje);
        } // procesar problemas que pueden ocurrir al enviar el objeto
        catch (IOException excepcionES) {
        }
    }

    // método utilitario que es llamado desde otros subprocesos para manipular a
    // areaPantalla en el subproceso despachador de eventos
    private void mostrarMensaje(final String mensajeAMostrar) {
        // mostrar mensaje del subproceso de ejecución despachador de eventos
        SwingUtilities.invokeLater(
                new Runnable() {  // clase interna para asegurar que la GUI se actualice apropiadamente
            public void run() // actualiza areaPantalla
            {
//               areaPantalla.append( mensajeAMostrar );
//               areaPantalla.setCaretPosition( 
//                  areaPantalla.getText().length() );
                System.out.println(mensajeAMostrar);
            }
        } // fin de la clase interna
                ); // fin de la llamada a SwingUtilities.invokeLater
    }
}
